
module spi_tx(
    input                           clk_i,
    input                           rstn_i,

    input                           tx_en_i,
    input   [1 :0]                  type_sel_i,
    input   [31:0]                  tx_i,
    input                           spi_CLK_pos_e_i,
    input                           spi_CLK_pos_r_i,

    output reg                      spi_tx_o,
    output reg                      spi_tx_done_o
);

localparam DATA1B_TYPE = 2'd0, ADDR_TYPE = 2'd1, COMD_TYPE = 2'd2;
localparam DATA1B_CNT  = 8   , ADDR_CNT  = 24  , COMD_CNT  = 8   ;

reg  [4 :0]              bit_cnt;
reg  [4 :0]              bit_cnt_max;
wire                     bit_cnt_flag;

reg  [31:0]              tx_mid;
reg  [31:0]              tx_reg;

wire                     first_bit;
always@(*)begin
    case (type_sel_i)
        DATA1B_TYPE: tx_mid = {tx_i[7:0], 24'd0}    ;
        ADDR_TYPE  : tx_mid = {tx_i[23:0], 8'd0}    ;
        COMD_TYPE  : tx_mid = {tx_i[7:0], 24'd0}    ;
        default    : tx_mid = {tx_i[7:0], 24'd0}    ;
    endcase    
end

always@(*)begin
    case (type_sel_i)
        DATA1B_TYPE: bit_cnt_max = DATA1B_CNT   ;
        ADDR_TYPE  : bit_cnt_max = ADDR_CNT     ;
        COMD_TYPE  : bit_cnt_max = COMD_CNT     ;
        default    : bit_cnt_max = COMD_CNT     ;
    endcase
end

assign bit_cnt_flag = (bit_cnt == bit_cnt_max-1) ? 1'b1 : 1'b0;
always@(posedge clk_i or negedge rstn_i)begin
    if(!rstn_i)begin
        bit_cnt <= 'd0;
    end
    else if((bit_cnt_flag && spi_CLK_pos_r_i) || !tx_en_i)begin
        bit_cnt <= 'd0;
    end
    else if(spi_CLK_pos_r_i)begin
        bit_cnt <= bit_cnt + 1'b1;
    end
end

always@(posedge clk_i or negedge rstn_i)begin
    if(!rstn_i)begin
        spi_tx_done_o <= 'd0;
    end
    else begin
        spi_tx_done_o <= (bit_cnt_flag & spi_CLK_pos_r_i) ? 1'b1 : 1'b0;
    end
end

assign first_bit = (bit_cnt == 'd0) ? 1'b1 : 1'b0;
always@(posedge clk_i or negedge rstn_i)begin
    if(!rstn_i)begin
        tx_reg <= 'd0;
    end
    else if(tx_en_i)begin
        if(first_bit) begin
            tx_reg <= spi_CLK_pos_e_i ? tx_mid : tx_reg;
        end
        else begin
            tx_reg <= spi_CLK_pos_e_i ? (tx_reg << 1) : tx_reg;
        end
    end
    else begin
        tx_reg <= 'd0;
    end
end

always@(*)begin
    spi_tx_o = tx_reg[31];
end
endmodule